namespace Xfinity.Physics
{
    /// <summary>
    /// A sample ODE that models an oscillating spring.
    /// </summary>
    public class SpringOde:Ode
    {
        private double mass;
        private double inverseMass;
        /// <summary>
        /// The mass at the end of the spring.
        /// </summary>
        public double Mass
        {
            get { return mass; }
            set { mass = value; inverseMass = 1 / mass; }
        }
        public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            
        }
        private double dampingCoefficient;

        /// <summary>
        /// The damping coefficient.
        /// </summary>
        public double DampingCoefficient
        {
            get { return dampingCoefficient; }
            set { dampingCoefficient = value; }
        }
        private double springConstant;

        /// <summary>
        /// The spring stiffness.
        /// </summary>
        public double SpringConstant
        {
            get { return springConstant; }
            set { springConstant = value; }
        }
        private double initialDisplacement;

        /// <summary>
        /// The initial position of the mass.
        /// </summary>
        public double InitialDisplacement
        {
            get { return initialDisplacement; }
            set { initialDisplacement = value; }
        }


        /// <summary>
        /// Constructs a new spring.
        /// </summary>
        /// <param name="mass">The mass at the end.</param>
        /// <param name="damping">The damping coefficient.</param>
        /// <param name="springConstant">The stiffness of the spring.</param>
        /// <param name="initialDeflection">The initial position of the spring.</param>
        public SpringOde(double mass, double damping, double springConstant, double initialDeflection):base(2)
        {
            this.Mass = mass;
            this.DampingCoefficient = damping;
            this.SpringConstant = springConstant;
            this.InitialDisplacement = initialDeflection;
            this.DependantVariables[0] = 0;
            this.DependantVariables[1] = initialDeflection;
        }

        /// <summary>
        /// Create a default spring.
        /// </summary>
        public SpringOde():this(0,0,0,0)
        {

        }

        //temp vars
        double velocity, location;
        double[] deltaDependant = new double[2];
        /// <summary>
        /// Evaluates the spring.
        /// </summary>
        /// <param name="time">The current time.</param>
        /// <param name="dependantVariables">All the current dependant variables.</param>
        /// <param name="deltaDependantVariables">The delta of the dependant variables.</param>
        /// <param name="deltaTime">The delta of the time.</param>
        /// <param name="dependantVariableScale">The position between 0 and 1 of the RK evaluation.</param>
        /// <returns>The new dependant variables.</returns>
        public override double[] EvaluateRightHandSide(double time, double[] dependantVariables, double[] deltaDependantVariables, double deltaTime, double dependantVariableScale)
        {
            velocity = dependantVariables[0] + dependantVariableScale * deltaDependantVariables[0];
            location = dependantVariables[1] + dependantVariableScale * deltaDependantVariables[1];

            deltaDependant[0] = -deltaTime * (dampingCoefficient * velocity + springConstant * location) * inverseMass;
            deltaDependant[1] = deltaTime * velocity;
            return deltaDependant;
        }
    }
}
